Skip to content

fix: prevent UI freezes from blocking SSH calls on remote branches#401

Merged
matt2e merged 4 commits intomainfrom
app-freezes-a-lot-for-remote
Mar 17, 2026
Merged

fix: prevent UI freezes from blocking SSH calls on remote branches#401
matt2e merged 4 commits intomainfrom
app-freezes-a-lot-for-remote

Conversation

@matt2e
Copy link
Contributor

@matt2e matt2e commented Mar 17, 2026

Summary

Fix UI freezes caused by has_unpushed_commits making blocking SSH round-trips (~5s each) on the Tauri IPC thread for remote branches.

Changes

  • Move git operations off the IPC thread — make has_unpushed_commits async and run the blocking SSH/git calls via spawn_blocking so they no longer freeze the UI.
  • Skip unnecessary checks for remote branches — remote workspace commits already live on the server, so skip the expensive hasUnpushedCommits call in BranchCardPrButton and ProjectHome for remote branches.
  • Scope safe-to-delete checks to visible projectssafeToDeleteProjects was iterating over all projects; now it only checks the ones currently rendered, avoiding wasted IPC round-trips.

matt2e added 3 commits March 17, 2026 16:20
Add a traced invoke wrapper (src/lib/invoke.ts) that logs every IPC
call to the Rust backend at info level with the command name and
wall-clock duration. Calls exceeding 100ms are tagged [SLOW] to make
it easy to spot UI-blocking operations when debugging remote project
freezes.

All four files that previously imported invoke directly from
@tauri-apps/api/core now use the wrapper:
- src/lib/commands.ts (main command wrappers)
- src/lib/features/actions/actions.ts (action commands)
- src/lib/features/branches/branch.ts (branch opener commands)
- src/lib/shared/persistentStore.ts (preferences store path)
The has_unpushed_commits command was the primary cause of UI freezes for
remote projects. It was called from three frontend sites and each remote
call did 2 synchronous SSH round-trips (~5s each) via blox ws_exec.

Call frequency: 10 calls in the first 25 seconds of app usage — fired
for every branch whenever branchesByProject changed (12 reassignment
sites in ProjectHome). Local branches completed in 39–202ms, but remote
branches blocked for 4.5–4.8s each.

Backend (prs.rs):
- Convert has_unpushed_commits from sync pub fn to async, wrapping the
  remote-branch SSH path in spawn_blocking so it no longer blocks the
  Tauri IPC thread.

Frontend — skip the check entirely for remote branches:
- ProjectHome.svelte safeToDeleteProjects $effect: treat merged remote
  branches as safe without the SSH check.
- ProjectHome.svelte handleDeleteProjectRequest: same skip.
- BranchCardPrButton.svelte: skip the per-timeline-refresh unpushed
  check for remote branches (isLocal guard).
The $effect that computes safeToDeleteProjects was iterating over all
projects, calling hasUnpushedCommits for every branch across every
project — even ones not currently displayed. Since the result is only
consumed in the {#each visibleProjects} render loop, this was wasted
work (and especially costly for remote branches with ~5s SSH
round-trips).

Narrow the loop from `projects` to `visibleProjects` so the check
only runs for the project the user is currently viewing.
@matt2e matt2e requested review from baxen and wesbillman as code owners March 17, 2026 05:40
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ddee15bd5f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

branches.map(async (branch) => {
const isMerged = branch.prState === 'MERGED';
if (!isMerged) return false;
if (branch.branchType === 'remote') return true;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve unpushed check before auto-deleting remote projects

Returning true for every merged remote branch here can incorrectly classify a project as safe to delete even when the remote workspace still has commits that were never pushed. start_repo_session with expected_outcome="commit" only creates commits (it does not require a push), so this state is reachable; then delete_project eventually calls remote cleanup that deletes the workspace (cleanup_branch_resources -> blox::ws_delete), which can drop those commits without showing the confirmation path.

Useful? React with 👍 / 👎.

const result = await tauriInvoke<T>(cmd, args);
const elapsed = performance.now() - start;
const tag = elapsed >= SLOW_THRESHOLD_MS ? ' [SLOW]' : '';
info(`[invoke]${tag} ${cmd} completed in ${elapsed.toFixed(1)}ms`);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard IPC timing logs when plugin-log is unavailable

This wrapper logs every invoke call via @tauri-apps/plugin-log, but the backend only installs tauri_plugin_log in debug builds (src-tauri/src/lib.rs under if cfg!(debug_assertions)), so release builds have no log plugin handler. Calling info(...) unconditionally here will generate rejected log calls for every IPC request, creating unhandled promise noise in production and potentially tripping global rejection handlers.

Useful? React with 👍 / 👎.

Delete src/lib/invoke.ts and revert all four import sites back to
importing invoke directly from @tauri-apps/api/core. The timing/logging
wrapper was added to diagnose the remote branch UI freeze and is no
longer needed now that the fix is in place.
@matt2e matt2e merged commit 9fc5479 into main Mar 17, 2026
4 checks passed
@matt2e matt2e deleted the app-freezes-a-lot-for-remote branch March 17, 2026 05:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant